########################################################################
#  Pyfm - personal finance data-base
#  Copyright (C) 2007,8 Ofer Barkai
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the 
# Free Software Foundation, Inc., 
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
########################################################################
"""A simple configuration database.

CONF is the configuration file path - $PYFM_HOME/conf.
    Its format is text lines with:
    
    key: value

    or (if ':' is not found),

    key = value

    Arbitrary amount of space can precede or follow the ':' (or '=').
    Comments start with '#'.
    Empty lines and comments are ignored.

get() is used to retrieve a configuration value given a key.

"""

import os
try:
    import threading
except ImportError:
    import dummy_threading as threading
import logging

# build_path and home should have been in dirs but there are circular dependcies with conf
import os

def build_path(sub,subdirs=[],bdir=None):
    if not bdir:
        bdir = get('DATA', 'data')
    d=[bdir]
    if sub: d.append(sub)
    if isinstance(subdirs,str):
        d.append(subdirs)
    else:
        d+=subdirs
    return os.path.join(*d)

def home(f=[], create=False):
    """Return the home directory for pyfm.

    The PYFM_HOME environment variable if it exists.
    Else, try ~/.pyfm, if it does not expand use the current directory.

    f - additional path components
    create - whether to create the resulting path if it does not exist
    """
    dir = os.path.expanduser('~/.pyfm')
    if dir.startswith('~'):
        dir = '.'
    dir = os.getenv('PYFM_HOME', dir)
    dir = build_path(None, subdirs=f, bdir=dir)
    if create and not os.path.exists(dir):
        os.makedirs(dir)
    return dir


__conf = None
__manual_lock = threading.Lock()
__manual_conf={}
# Default values if no default is specificed in get(). 
# If a key is used in more than one place, it is better to specificy its default value here
# and not to repeat the default in all places in which the get(key) is performed.
__default_conf = {'ONLINE':'TRUE', 'CURDEF':'USD'}


def read(name):
    conf = {}
    try:
        f = open(name)
    except:
        return conf
    try:
        for l in f:
            i = l.find('#')
            if i >= 0:
                l = l[:i]
            if len(l.strip()) == 0:
                continue
            if l.find('=') >= 0:
                sep = '='
            elif l.find(':') >= 0:
                sep = ':'
            else:
                raise Exception('bad config line')
            key, value = l.split(sep)
            key = key.strip()
            value = value.strip()
            conf[key] = value
    finally:
        f.close()
    return conf


def get(key, default=None):
    """ Retrieve a configuration value.

    First manual_conf is searched for <key>, then the environment
    variable PYFM_<key>, and finally (if <key> was not yet found),
    the configuration file (<pyfm home>/conf) is searched (the file
    is read once at the first time it is needed).

    key - a string containing the key to the value we want
    default - a default value that is returned in key does not exist

    """
    global __manual_lock
    global __manual_conf
    global __conf
    value = []
    __manual_lock.acquire()
    if key in __manual_conf:
        value.append(__manual_conf[key])
    __manual_lock.release()
    if value:
        return value[0]
    if 'PYFM_'+key in os.environ:
        return os.environ['PYFM_'+key]
    if __conf==None: # Dont use "not" because "not {}" is also True
        __conf = read(os.path.join(home([], True), 'conf'))
    if key in __conf:
        return __conf[key]
    if default != None:
        return default
    return __default_conf.get(key,None)

logging_levels={'DEBUG':logging.DEBUG,
                'INFO':logging.INFO,
                'WARNING':logging.WARNING,
                'ERROR':logging.ERROR,
                'CRITICAL':logging.CRITICAL,
            }

def manual_set(key, value):
    global __manual_lock
    global __manual_conf
    __manual_lock.acquire()
    __manual_conf[key] = value
    if key == 'LOGGING':
        logging.root.setLevel(logging_levels[value])
    __manual_lock.release()


logging.root.setLevel(logging_levels[get('LOGGING','ERROR')])
logging.basicConfig(format='%(message)s')


if __name__=='__main__': print get('DATA')
